package com.yuqiaotech.zcj.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * 基于hibernate的数据操作类。
 * 
 * @author YUQIAOTECH
 * 
 */
public class BaseDao extends HibernateDaoSupport {

	/**
	 * 保存对象。 这里调用的是merge方法。
	 * 
	 * @param o
	 * @return
	 */
	public Object save(Object o) {
		return this.getHibernateTemplate().merge(o);
	}

	/**
	 * 删除对象。
	 * 
	 * @param o
	 */
	public void delete(Object o) {
		this.getHibernateTemplate().delete(o);
	}

	public void remove(Class entityClass, Serializable id) {
		Object o = this.get(entityClass, id);
		this.getHibernateTemplate().delete(o);
	}

	/**
	 * 根据主键获取。
	 * 
	 * @param entityClass
	 * @param id
	 * @return
	 */
	public Object get(Class entityClass, Serializable id) {
		return this.getHibernateTemplate().get(entityClass, id);
	}

	/**
	 * 执行查询HQL。
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public List executeQuery(String hql, Object... params) {
		return this.getHibernateTemplate().find(hql, params);
	}

	public List executeQuery(String hql) {
		return this.executeQuery(hql, null);
	}

	public int executeUpdate(String hql) {
		return executeUpdate(hql, null);
	}

	/**
	 * 执行更新操作的hql。
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public int executeUpdate(String hql, Object... params) {
		return this.getHibernateTemplate().bulkUpdate(hql, params);
	}

	/**
	 * 根据某个有唯一值的字段获取。
	 * 
	 * @param persistentClass
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public Object findUniqueBy(Class persistentClass, String propertyName,
			Object value) {
		Criteria criteria = getSession().createCriteria(persistentClass);
		return criteria.add(Restrictions.eq(propertyName, value))
				.uniqueResult();
	}

	/**
	 * QBC方式查询。
	 * 
	 * @param detachedCriteria
	 * @return
	 */
	public List findByCriteria(final DetachedCriteria detachedCriteria) {
		return (List) getHibernateTemplate().execute(
				new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				Criteria criteria = detachedCriteria
						.getExecutableCriteria(session);
				List items = criteria.list();
				return items;
			}
		});
	}

	/**
	 * QBC方式，并且分页。
	 * 
	 * @param detachedCriteria
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public PaginationSupport paginateByCriteria(
			DetachedCriteria detachedCriteria, int pageNo, int pageSize) {
		int start = (pageNo - 1) * pageSize;
		return findPageByCriteria(detachedCriteria, start, pageSize);
	}

	/**
	 * 注意这里参数的意义，startIndex，是起始记录序号而不是页码。
	 * 另外需要注意的是对于非lazy方式关联的对象使用Criteria执行的结果的内容。
	 * 
	 * @param detachedCriteria
	 * @param startIndex
	 * @param pageSize
	 * @return
	 */
	public PaginationSupport findPageByCriteria(
			final DetachedCriteria detachedCriteria, final int startIndex,
			final int pageSize) {
		return (PaginationSupport) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						int start = startIndex;
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						int totalCount = ((Integer) criteria.setProjection(
								Projections.rowCount()).uniqueResult())
								.intValue();
						criteria.setProjection(null);
						if (start > totalCount && totalCount > 0) {
							start = (totalCount - 1) / pageSize * pageSize;
						}
						// criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
						// //Each row of results is a distinct
						// instance of the root entity
						List items = criteria.setFirstResult(start)
								.setMaxResults(pageSize).list();
						PaginationSupport ps = new PaginationSupport(items,
								totalCount, start, pageSize);
						return ps;
					}
				});
	}

	/**
	 * 根据hql进行获取分页对象。
	 * 
	 * @param hql
	 * @param pageNo
	 * @param pageSize
	 * @param values
	 * @return
	 */
	public PaginationSupport paginationByHql(final String hql,
			final int pageNo, final int pageSize, final Object... values) {
		int startIndex = (pageNo - 1) * pageSize;
		return findPageByHql(hql, null, startIndex, pageSize, values);
	}

	public PaginationSupport paginationByHql(final String hql,
			final String vCountHql, final int pageNo, final int pageSize,
			final Object... values) {
		int startIndex = (pageNo - 1) * pageSize;
		return findPageByHql(hql, vCountHql, startIndex, pageSize, values);
	}

	public PaginationSupport findPageByHql(final String hql,
			final int startIndex, final int pageSize, final Object... values) {
		return findPageByHql(hql, null, startIndex, pageSize, values);
	}

	/**
	 * 注意这里参数的意义，startIndex，是起始记录序号而不是页码。 注意代码里的countHql的处理，对于有些情况可能会不适用。
	 * 
	 * @param hql
	 * @param vCountHql
	 * @param startIndex
	 * @param pageSize
	 * @param values
	 * @return
	 */
	public PaginationSupport findPageByHql(final String hql,
			final String vCountHql, final int startIndex, final int pageSize,
			final Object... values) {
		return (PaginationSupport) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Integer totalCount = 0;
						String countHql = vCountHql;
						if (countHql == null) {
							countHql = getCountHql(hql);
						}
						Number r = (Number) prepareQuery(session, countHql,
								values).uniqueResult();
						if (r != null)
							totalCount = r.intValue();
						if (totalCount == 0) {
							return new PaginationSupport(new ArrayList(), 0,
									startIndex, pageSize);
						}
						Query query = prepareQuery(session, hql, values);
						if (startIndex > 0) {
							query.setFirstResult(startIndex);
						}
						if (pageSize > 0) {
							query.setMaxResults(pageSize);
						}
						List items = query.list();
						PaginationSupport ps = new PaginationSupport(items,
								totalCount, startIndex, pageSize);
						return ps;
					}
				});
	}

	private Query prepareQuery(Session session, String hql, Object[] values) {
		Query query = session.createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}

	private String getCountHql(String hql) {
		int fromIndex = hql.toLowerCase().indexOf("from");
		String countHql = hql.substring(fromIndex);
		int orderByIndex = countHql.toLowerCase().indexOf("order by");
		if (orderByIndex != -1) {
			countHql = countHql.substring(0, orderByIndex);
		}
		return "select count(*) " + countHql;
	}
}
